package test.panel4;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.ArrayList;
import java.util.List;

public class ResourceGUI {
    public JPanel rowPanel;
    private static final ResourceGUI instance = new ResourceGUI();

    public static ResourceGUI getInstance() {
        return instance;
    }

    public JPanel frame;
    private JPanel resourcePanel;
    private JButton addButton;
    private JButton confirmButton;
    private JTable resourceTable;
    private DefaultTableModel tableModel;
    private int resourceCount = 0;
    private final ArrayList<JPanel> resourceRows;
    private final ArrayList<JTextField> resourceFields;
    private final ArrayList<Resource> resources;

    private ResourceGUI() {
        resourceRows = new ArrayList<>();
        resourceFields = new ArrayList<>();
        resources = new ArrayList<>();
        initialize();
    }

    private void initialize() {
        frame = new JPanel();
        frame.setPreferredSize(new Dimension(600, 350)); // 设置首选大小
        frame.setLayout(new BorderLayout());

        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        addButton = new JButton("添加");
        confirmButton = new JButton("确认");
        topPanel.add(addButton);
        topPanel.add(confirmButton);

        resourcePanel = new JPanel();
        resourcePanel.setLayout(new BoxLayout(resourcePanel, BoxLayout.Y_AXIS)); // 垂直布局

        JScrollPane scrollPane = new JScrollPane(resourcePanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); // 垂直滚动条根据需要显示

        // 创建资源表模型
        String[] columnNames = {"资源ID", "总数", "剩余数"};
        tableModel = new DefaultTableModel(columnNames, 0);
        resourceTable = new JTable(tableModel);
        JScrollPane tableScrollPane = new JScrollPane(resourceTable);

        addButton.addActionListener(e -> addResourceField());

        confirmButton.addActionListener(e -> {
            confirmResources();
            updateResourceSummary();
        });

        frame.add(topPanel, BorderLayout.NORTH);
        frame.add(scrollPane, BorderLayout.CENTER); // 在中心添加可滚动的面板
        frame.add(tableScrollPane, BorderLayout.EAST); // 右侧添加表格

        frame.setVisible(true);
    }

    private int nextResourceId = 1; // 定义一个成员变量来跟踪下一个可用的资源ID

    private void addResourceField() {
        // 使用 nextResourceId 作为资源 ID，保证 ID 连续
        int resourceId = nextResourceId++;

        // 创建新的资源行
        JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        final int finalResourceId = resourceId;

        JLabel label = new JLabel(finalResourceId + ". ");
        JTextField textField = new JTextField(10);
        JButton deleteButton = new JButton("删除");

        deleteButton.addActionListener(e -> {
            // 使用捕获的 final 变量来调用删除方法
            deleteResourceField(rowPanel, finalResourceId); // 删除当前资源行
        });

        rowPanel.add(label);
        rowPanel.add(textField);
        rowPanel.add(deleteButton);

        rowPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, rowPanel.getPreferredSize().height));

        // 将每个新添加的资源行加入到列表中
        resourceRows.add(rowPanel);
        resourceFields.add(textField);
        resources.add(new Resource(resourceId, 0)); // 初始资源为 0

        resourcePanel.add(rowPanel);
        resourcePanel.revalidate();
        resourcePanel.repaint();
    }

    private void deleteResourceField(JPanel rowPanel, int resourceId) {
        // 从资源面板中移除对应的行
        resourcePanel.remove(rowPanel);

        // 从资源列表中移除对应的资源
        resources.removeIf(r -> r.getId() == resourceId);

        // 找到该行的索引并从资源行和资源字段的集合中移除
        int index = resourceRows.indexOf(rowPanel);
        if (index != -1) {
            resourceRows.remove(index);
            resourceFields.remove(index);
        }

        // 更新 nextResourceId 以确保它始终比已有的任何 resourceId 大
        nextResourceId = resources.stream()
                .mapToInt(Resource::getId)
                .max()
                .orElse(0) + 1;

        // 刷新面板并强制重绘
        SwingUtilities.invokeLater(() -> {
            resourcePanel.revalidate();
            resourcePanel.repaint();
        });

        // 只更新右侧资源表格，无需更新左侧的ID
        updateResourceSummary();
    }


    private void confirmResources() {
        List<Resource> updatedResources = new ArrayList<>();

        for (int i = 0; i < resourceRows.size(); i++) {
            JPanel rowPanel = resourceRows.get(i);
            JTextField textField = resourceFields.get(i);

            try {
                int resourceAmount = Integer.parseInt(textField.getText());

                // 获取原始的 Resource 对象以保持原有的 resourceId
                JLabel label = (JLabel) rowPanel.getComponent(0); // 假设label是第一个组件
                int resourceId = Integer.parseInt(label.getText().split("\\.")[0].trim()); // 解析真实的resourceId

                // 使用原始的 resourceId 创建新的 Resource 对象
                Resource resource = new Resource(resourceId, resourceAmount);
                updatedResources.add(resource);
            } catch (NumberFormatException e) {
                JOptionPane.showMessageDialog(frame, "请输入有效的数字", "输入错误", JOptionPane.ERROR_MESSAGE);
                return; // 如果有错误发生，立即返回，不更新资源
            }
        }

        // 更新资源列表
        resources.clear();
        resources.addAll(updatedResources);

        // 更新右侧资源表格
        updateResourceSummary();
    }

    private void updateResourceSummary() {
        tableModel.setRowCount(0);  // 清除现有的数据
        for (Resource resource : resources) {
            int remaining = resource.getAmount(); // 你需要根据实际业务逻辑计算剩余资源
            Object[] row = {resource.getId(), resource.getOriginalAmount(), remaining};
            tableModel.addRow(row);
        }
    }

    private static class Resource {
        private final int id;
        private final int originalAmount;
        private int amount;

        public Resource(int id, int amount) {
            this.id = id;
            this.originalAmount = amount;
            this.amount = amount;
        }

        public int getId() {
            return id;
        }

        public int getOriginalAmount() {
            return originalAmount;
        }

        public int getAmount() {
            return amount;
        }

        public void setAmount(int amount) {
            this.amount = amount;
        }
    }

    public boolean checkAndAllocateResources(Process process) {
        Map<Integer, Integer> needs = process.getNeeds();
        Map<Integer, Integer> available = new HashMap<>();
        for (Resource resource : resources) {
            available.put(resource.getId(), resource.getAmount());
        }

        boolean allocated = canAllocate(needs, available, Control.running_process, process.pid);

        if (allocated) {
            process.allocateResources(needs); // 为进程实际分配资源
            for (Map.Entry<Integer, Integer> entry : needs.entrySet()) {
                int resourceId = entry.getKey();
                int allocatedAmount = entry.getValue();
                Resource resource = getResourceById(resourceId);
                resource.setAmount(resource.getAmount() - allocatedAmount); // 减少系统资源
            }
            updateResourceSummary(); // 更新显示
        } else {
            JOptionPane.showMessageDialog(frame, "资源不足，无法分配给进程 " + process.pid, "资源分配失败", JOptionPane.WARNING_MESSAGE);
        }

        return allocated;
    }

    private boolean isSafeState(Map<Integer, Integer> available, Map<Integer, Process> running_process) {
        Map<Integer, Integer> work = new HashMap<>(available);
        Set<Integer> finished = new HashSet<>();

        while (finished.size() < running_process.size()) {
            boolean found = false;

            for (Map.Entry<Integer, Process> entry : running_process.entrySet()) {
                int processId = entry.getKey();
                Process process = entry.getValue();

                if (finished.contains(processId)) continue;

                boolean canFinish = true;

                for (Map.Entry<Integer, Integer> need : process.getNeeds().entrySet()) {
                    int resourceId = need.getKey();
                    int requiredAmount = need.getValue();
                    if (requiredAmount > work.getOrDefault(resourceId, 0)) {
                        canFinish = false;
                        break;
                    }
                }

                if (canFinish) {
                    for (Map.Entry<Integer, Integer> allocation : process.getAllocation().entrySet()) {
                        int resourceId = allocation.getKey();
                        int allocatedAmount = allocation.getValue();
                        work.put(resourceId, work.get(resourceId) + allocatedAmount);
                    }
                    finished.add(processId);
                    found = true;
                }
            }

            if (!found) {
                return false;
            }
        }

        return true;
    }

    private boolean canAllocate(Map<Integer, Integer> needs, Map<Integer, Integer> available, Map<Integer, Process> running_process, int processId) {
        for (Map.Entry<Integer, Integer> entry : needs.entrySet()) {
            int resourceId = entry.getKey();
            int requiredAmount = entry.getValue();
            int availableAmount = available.getOrDefault(resourceId, 0);
            if (requiredAmount > availableAmount) {
                return false;
            }
        }

        Map<Integer, Integer> availableCopy = new HashMap<>(available);
        Map<Integer, Process> runningCopy = new HashMap<>();

        for (Map.Entry<Integer, Integer> entry : needs.entrySet()) {
            int resourceId = entry.getKey();
            int requiredAmount = entry.getValue();
            availableCopy.put(resourceId, availableCopy.get(resourceId) - requiredAmount);
        }

        Process process = running_process.get(processId);
        Process simulatedProcess = new Process(process.name, process.isRunning, new HashMap<>(process.Needs));
        Process.nextPid--;

        simulatedProcess.allocateResources(needs);
        for (Map.Entry<Integer, Integer> entry : needs.entrySet()) {
            int resourceId = entry.getKey();
            simulatedProcess.Needs.put(resourceId, 0);
        }

        runningCopy.putAll(running_process);
        runningCopy.put(processId, simulatedProcess);

        return isSafeState(availableCopy, runningCopy);
    }

    private Resource getResourceById(int resourceId) {
        for (Resource resource : resources) {
            if (resource.getId() == resourceId) {
                return resource;
            }
        }
        return null;
    }

    public void releaseResources(Process process) {
        Map<Integer, Integer> allocation = process.getAllocation();

        for (Map.Entry<Integer, Integer> entry : allocation.entrySet()) {
            int resourceId = entry.getKey();
            int allocatedAmount = entry.getValue();

            Resource resource = getResourceById(resourceId);
            if (resource != null) {
                resource.setAmount(resource.getAmount() + allocatedAmount);
            }
        }

        process.clearAllocation();
        updateResourceSummary();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ResourceGUI::new);
    }
}
